using System;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;

namespace Voodoo.Meta
{
	public class Leaderboard : MonoBehaviour
	{
		[Header("Project Reference")]
		[SerializeField]
		private LeaderboardConfigData _config;

		[Header("Hierarchy References")]
		[SerializeField]
		private Canvas _canvas;

		[SerializeField]
		private Canvas _interactionCanvas;

		[SerializeField]
		private LeaderboardLayout _layout;

		private LeaderboardAudio _audio;

		private LeaderboardHaptic _haptic;

		private CancellationTokenSource _interactionCanvasCancelSource;

		private Action _leaderboardEnded;

		private int _rankVibrationThreshold;

		private CancellationTokenSource _vibrationCancelSource;

		public static Leaderboard First { get; private set; }

		public bool IsVisible => _canvas.enabled;

		public bool IsInteractionCanvasVisible => _interactionCanvas.gameObject.activeSelf;

		private void Awake()
		{
			_audio = GetComponent<LeaderboardAudio>();
			_haptic = GetComponent<LeaderboardHaptic>();
			if (First == null)
			{
				First = this;
			}
		}

		private void OnEnable()
		{
			_layout.rankUpdated += OnRankUpdated;
			_layout.rankProgressionProcessed += OnRankProgressionProcessed;
		}

		private void OnDisable()
		{
			_layout.rankUpdated -= OnRankUpdated;
			_layout.rankProgressionProcessed -= OnRankProgressionProcessed;
		}

		public void SetPlayerInfo(string playerName, Sprite playerFlag)
		{
			_layout.SetPlayerInfo(playerName, playerFlag);
		}

		public void Show(int previousScore, int newScore, Action onComplete = null)
		{
			ShowAsync(previousScore, newScore, onComplete).ConfigureAwait(continueOnCapturedContext: false);
		}

		public void Show(int previousScore, int newScore, string playerName, Sprite playerFlag = null, Action onComplete = null)
		{
			SetPlayerInfo(playerName, playerFlag);
			Show(previousScore, newScore, onComplete);
		}

		public void Next()
		{
			if (_config.allowAnimationSkip)
			{
				if (_interactionCanvas.enabled)
				{
					Stop();
				}
				else
				{
					ShowInteractionCanvas();
				}
			}
		}

		public int GetNextRank(int previousScore, int newScore)
		{
			return _layout.GetNextRank(previousScore, newScore);
		}

		public int GetNextRankFromStep(int previousScore, int newScore, int rankStep)
		{
			return _layout.GetNextRankFromStep(previousScore, newScore, rankStep);
		}

		public int GetRankEarned(int newScore)
		{
			return _layout.GetRankEarned(newScore);
		}

		public void Stop()
		{
			_layout.Hide();
			LeaderboardHideFeedback();
			SetCanvasVisibility(_canvas, isVisible: false);
			SetCanvasVisibility(_interactionCanvas, isVisible: false);
			_leaderboardEnded?.Invoke();
		}

		public void Restart(int previousScore, int newScore)
		{
			_layout.Hide();
			LeaderboardHideFeedback();
			SetCanvasVisibility(_canvas, isVisible: false);
			SetCanvasVisibility(_interactionCanvas, isVisible: false);
			ShowAsync(previousScore, newScore, _leaderboardEnded).ConfigureAwait(continueOnCapturedContext: false);
		}

		private async Task ShowAsync(int previousScore, int newScore, Action onComplete = null)
		{
			await Task.Yield();
			_leaderboardEnded = onComplete;
			SetCanvasVisibility(_canvas, isVisible: true);
			if (_config.allowAnimationSkip)
			{
				SetInteractionCanvasActive(isActive: true, _config.delaySkipBtn);
			}
			int playerRank = _layout.GetPlayerRank();
			if (10000 > playerRank && playerRank > 1)
			{
				LeaderboardShowFeedback();
			}
			_layout.Initialize(previousScore, newScore);
			_rankVibrationThreshold = Mathf.RoundToInt(_config.vibrationThreshold * (float)_layout.GetRankEarned(newScore));
			if (_haptic != null)
			{
				_haptic.Initialize(_rankVibrationThreshold);
			}
			await _layout.ShowAsync();
			if (!_config.allowAnimationSkip)
			{
				Stop();
			}
		}

		private void ShowInteractionCanvas()
		{
			_interactionCanvasCancelSource.Cancel();
		}

		private void SetCanvasVisibility(Canvas canvas, bool isVisible)
		{
			canvas.enabled = isVisible;
		}

		private async Task SetInteractionCanvasActiveAsync(bool isActive, float delay)
		{
			try
			{
				_interactionCanvasCancelSource = new CancellationTokenSource();
				await Task.Delay(TimeSpan.FromSeconds(delay), _interactionCanvasCancelSource.Token);
			}
			catch (OperationCanceledException)
			{
			}
			finally
			{
				SetCanvasVisibility(_interactionCanvas, isActive);
			}
		}

		private void SetInteractionCanvasActive(bool isActive, float delay)
		{
			SetInteractionCanvasActiveAsync(isActive, delay).ConfigureAwait(continueOnCapturedContext: false);
		}

		private void LeaderboardShowFeedback()
		{
			AudioClip rollSFX = _config.rollSFX;
			if (rollSFX != null && _audio != null)
			{
				_audio.Play(rollSFX);
			}
			if (_haptic != null)
			{
				_haptic.VibrateOnAnimationStart();
			}
		}

		private void LeaderboardHideFeedback()
		{
			if (_audio != null)
			{
				_audio.Stop();
			}
		}

		private void PlayerRankFeedback()
		{
			AudioClip endSFXOneShot = _config.endSFXOneShot;
			if (endSFXOneShot != null && _audio != null)
			{
				_audio.PlayOneShot(endSFXOneShot);
			}
			if (_haptic != null)
			{
				_haptic.VibrateOnAnimationEnd();
			}
		}

		private void PlayerRankProgressionFeedback(int rank)
		{
			if (_haptic != null)
			{
				_haptic.VibrateWhenRankClimbing(rank);
			}
		}

		private void OnRankUpdated()
		{
			PlayerRankFeedback();
		}

		private void OnRankProgressionProcessed(int rank)
		{
			PlayerRankProgressionFeedback(rank);
		}
	}
}
